/*=================================================
Author: Peter Hammett
License: MIT License (MIT)
This firmware is open source and free to use and distribute
==================================================*/

/*==================================================
EEProm locations
All in twos compliment 
Add 128 to store
Subtract 128 to retrieve
0 latDeg 
1 latMin
2 lonDeg
3 lonMin
4 timezone
5 dlstime
====================================================*/

#include <Wire.h>
#include <SunLamp.h>
#include <EEPROM.h>
#include <ClickButton.h>
#include <PinChangeInt.h>
#include <AdaEncoder.h>

#define PINA 10
#define PINB 9
#define DS1307_ADDRESS 0x68
byte zero = 0x00;

int8_t clicks = 0;
char id = 0;

const int led = 6;
const int buttonPin = 12;

SunLamp lamp(13);
ClickButton button(buttonPin, LOW, CLICK_PULLUP);

double latDeg = 0;
double latMin = 0;
double lat = 0;
double lonDeg = 0;
double lonMin = 0;
double lon = 0;
double timezone = 0;
double dlstime = 0;
double lightPower = 0;
int setupMonth = 0;
int setupDay = 0;
int setupYear = 0;
int setupHour = 0;
int setupMin = 0;
int setupSec = 0;
int lastClickCode = 0;
int encoderVal = 0;
int lastEncoderVal = 0;
int menuState = 0;

void setup(){
  Serial.begin(9600);
  Wire.begin();
  pinMode(led, OUTPUT);
  AdaEncoder::addEncoder('a', PINA, PINB);
//  EEPROM.write(0, (42+128));
//  EEPROM.write(1, (35+128)); 
//  EEPROM.write(2, (-71+128)); 
//  EEPROM.write(3, (05+128)); 
//  EEPROM.write(4, (-5+128)); 
//  EEPROM.write(5, (1+128)); 
    
  latDeg = EEPROM.read(0) - 128;
  latMin = EEPROM.read(1) - 128;
  lonDeg = EEPROM.read(2) - 128;
  lonMin = EEPROM.read(3) - 128;
  timezone = EEPROM.read(4) - 128;
  dlstime = EEPROM.read(5) - 128;
//  Serial.print("latDeg");
//  Serial.println(latDeg);
//  Serial.print("latMin");
//  Serial.println(latMin);
//  Serial.print("lonDeg");
//  Serial.println(lonDeg);
//  Serial.print("lonMin");
//  Serial.println(lonMin);
//  Serial.print("timezone");
//  Serial.println(timezone);
//  Serial.print("dlstime");
//  Serial.println(dlstime);
}

long oldPosition = -999;

void loop(){
  button.Update();
  encoder *thisEncoder;
  thisEncoder=AdaEncoder::genie(&clicks, &id);
  if (thisEncoder != NULL) {
    if (clicks > 0) {
      encoderVal--;
    }
    if (clicks < 0) {
      encoderVal++;
    }
  }
  if(button.click == CLICK_SINGLEHOLD && button.click != lastClickCode){
    Wire.beginTransmission(DS1307_ADDRESS);
    Wire.write(zero);
    Wire.endTransmission();
  
    Wire.requestFrom(DS1307_ADDRESS, 7);
  
    int tempsecond = bcdToDec(Wire.read());
    int tempminute = bcdToDec(Wire.read());
    int temphour = bcdToDec(Wire.read() & 0b111111); //24 hour time
    int tempweekDay = bcdToDec(Wire.read()); //0-6 -> sunday - Saturday
    int tempmonthDay = bcdToDec(Wire.read());
    encoderVal = bcdToDec(Wire.read());
    int tempyear = bcdToDec(Wire.read());
    //Serial.print("Month: ");
    //Serial.println(encoderVal);
    menuState = 1;
  }
  switch (menuState){
    case 0:
      {
      	  Wire.beginTransmission(DS1307_ADDRESS);
	  Wire.write(zero);
	  Wire.endTransmission();
	
	  Wire.requestFrom(DS1307_ADDRESS, 7);
	
	  int calcsecond = bcdToDec(Wire.read());
	  int calcminute = bcdToDec(Wire.read());
	  int calchour = bcdToDec(Wire.read() & 0b111111); //24 hour time
	  int tempweekDay = bcdToDec(Wire.read()); //0-6 -> sunday - Saturday
	  int calcmonthDay = bcdToDec(Wire.read());
	  int calcmonth = bcdToDec(Wire.read());
	  int calcyear = bcdToDec(Wire.read());
	  double JD = lamp.calcJD(calcyear,calcmonth,calcmonthDay);
	  double T = lamp.calcTimeJulianCent(JD);
	  double lat = latDeg + (latMin * .01);
	  double lon = lonDeg + (lonMin * .01);
	  double sunrise = lamp.sunrise(lat, lon, JD, timezone, dlstime);
	  double noon = lamp.solarnoon(lat, lon, JD, timezone, dlstime);
	  double sunset = lamp.sunset(lat, lon, JD, timezone, dlstime);
	  if (((calchour * 60) + calcminute) < noon){
		//do sunrise calcs
		double time = (calchour * 60) + calcminute;
		double mDiff = noon - sunrise;
		double m = 255 / mDiff;
		double b = (m * sunrise) * -1;
		lightPower = round((m * time) + b);
		if (lightPower > 255) {
		  lightPower = 255;
		} else if(lightPower < 0) {
		  lightPower = 0;
		}
		analogWrite(led, lightPower);
	  } else {
		//do sunset calcs
		double time = (calchour * 60) + calcminute;
		double mDiff = sunset - noon;
		double m = -255/mDiff;
		double b = (m * sunset) * -1;
		lightPower = round((m*time)+b);
		if (lightPower > 255) {
		  lightPower = 255;
		} else if(lightPower < 0) {
		  lightPower = 0;
		}
		analogWrite(led, lightPower);
          }
          
          printDate();
	  Serial.print("Power: ");
	  Serial.println(lightPower);
	  delay(1000);
      }
      break;
    case 1:
      if (encoderVal > 12) encoderVal = 1;
      if (encoderVal < 1) encoderVal = 12;
      if (encoderVal != lastEncoderVal){
         Serial.print("Month: ");
         Serial.println(encoderVal); 
      }
      if(button.click == CLICK_SINGLECLICKED && button.click != lastClickCode){
        setupMonth = encoderVal;
        Wire.beginTransmission(DS1307_ADDRESS);
        Wire.write(zero);
        Wire.endTransmission();
      
        Wire.requestFrom(DS1307_ADDRESS, 7);
      
        int tempsecond = bcdToDec(Wire.read());
        int tempminute = bcdToDec(Wire.read());
        int temphour = bcdToDec(Wire.read() & 0b111111); //24 hour time
        int tempweekDay = bcdToDec(Wire.read()); //0-6 -> sunday - Saturday
        encoderVal = bcdToDec(Wire.read());
        int tempmonth = bcdToDec(Wire.read());
        int tempyear = bcdToDec(Wire.read());
        Serial.print("Day: ");
        Serial.print(encoderVal);
        Serial.println("");
        menuState = 2;
      }
      break;
    case 2: 
      if (encoderVal > 31) encoderVal = 1;
      if (encoderVal < 1) encoderVal = 31;
      if (encoderVal != lastEncoderVal){
         Serial.print("Day: ");
         Serial.println(encoderVal); 
      }
      if(button.click == CLICK_SINGLECLICKED && button.click != lastClickCode){
      setupDay = encoderVal;
      Wire.beginTransmission(DS1307_ADDRESS);
      Wire.write(zero);
      Wire.endTransmission();
    
      Wire.requestFrom(DS1307_ADDRESS, 7);
    
      int tempsecond = bcdToDec(Wire.read());
      int tempminute = bcdToDec(Wire.read());
      int temphour = bcdToDec(Wire.read() & 0b111111); //24 hour time
      int tempweekDay = bcdToDec(Wire.read()); //0-6 -> sunday - Saturday
      int tempDay = bcdToDec(Wire.read());
      int tempmonth = bcdToDec(Wire.read());
      encoderVal = bcdToDec(Wire.read());
      Serial.print("Year: ");
      Serial.print(encoderVal);
      Serial.println("");
      menuState = 3;
      }
      break;
    case 3: 
      if (encoderVal > 100) encoderVal = 0;
      if (encoderVal < 0) encoderVal = 100;
      if (encoderVal != lastEncoderVal){
        Serial.print("Year: ");
        Serial.println(encoderVal);
      }
      if(button.click == CLICK_SINGLECLICKED && button.click != lastClickCode){
        setupYear = encoderVal;
        Wire.beginTransmission(DS1307_ADDRESS);
        Wire.write(zero);
        Wire.endTransmission();
      
        Wire.requestFrom(DS1307_ADDRESS, 7);
      
        int tempsecond = bcdToDec(Wire.read());
        int tempminute = bcdToDec(Wire.read());
        encoderVal = bcdToDec(Wire.read() & 0b111111); //24 hour time
        int tempweekDay = bcdToDec(Wire.read()); //0-6 -> sunday - Saturday
        int tempDay = bcdToDec(Wire.read());
        int tempmonth = bcdToDec(Wire.read());
        int tempyear = bcdToDec(Wire.read());
        Serial.print("Hour: ");
        Serial.print(encoderVal);
        Serial.println("");
        menuState = 0; 
      break;
      }   
   }
  lastClickCode = button.click;
  lastEncoderVal = encoderVal;
}

byte decToBcd(byte val){
// Convert normal decimal numbers to binary coded decimal
  return ( (val/10*16) + (val%10) );
}

byte bcdToDec(byte val)  {
// Convert binary coded decimal to normal decimal numbers
  return ( (val/16*10) + (val%16) );
}

void printDate(){

  // Reset the register pointer
  Wire.beginTransmission(DS1307_ADDRESS);
  Wire.write(zero);
  Wire.endTransmission();

  Wire.requestFrom(DS1307_ADDRESS, 7);

  int tempsecond = bcdToDec(Wire.read());
  int tempminute = bcdToDec(Wire.read());
  int temphour = bcdToDec(Wire.read() & 0b111111); //24 hour time
  int tempweekDay = bcdToDec(Wire.read()); //0-6 -> sunday - Saturday
  int tempmonthDay = bcdToDec(Wire.read());
  int tempmonth = bcdToDec(Wire.read());
  int tempyear = bcdToDec(Wire.read());

  //print the date EG   3/1/11 23:59:59
  Serial.print(tempmonth);
  Serial.print("/");
  Serial.print(tempmonthDay);
  Serial.print("/");
  Serial.print(tempyear);
  Serial.print(" ");
  Serial.print(temphour);
  Serial.print(":");
  Serial.print(tempminute);
  Serial.print(":");
  Serial.println(tempsecond);
}
